Annotation 要怎麼定義會影響使用這個 library 的使用者體驗,annotation 必須要好理解而且還要具有可擴充性。我們的目標是要方便使用者獲取 RSS 格式裡面的資料,所以我們可以就資料層面來看這件事情。在 RSS 格式裡,有三個重要的元素:
<title>
這種東西,他除了有許多不同的 tag ,也可能有自訂的 tag 。<title attr="Attribute">
,這個也能夠自定義。<title>This is a value</title>
。透過從資料中拆解出這三個元素,我們可以設計三個 annotation 去分別定義這三個資料型態。透過 Kotlin 的 data class 和 annotation ,我們可以組合出許多自定義的資料。這三個資料型態分別又對應了...
@RssTag
@RssAttribute
@RssValue
假如現在使用者有個需求是不同的 tag 想要擺在 Kotlin data class 的同一個變數或是 property 底下,那這三個 annotation 可能都無法滿足這個需求,因為以上這三個都是只能處理單個 tag 或是 單個值。因此,我們需要設計一個 annotation 讓使用者可以把不同 tag 的資料按優先順序放到指定的 data class 裡面,那個 annotation 就是 @RssRawData
。
讓我們來看看對應的資料會長怎麼樣吧!假設我們有一個 RSS 的資料:
<channel customAttr="attr">
<title>the title</title>
<itunes:title>itunes title</itunes:title>
<googleplay:description>google play desc</googleplay:description>
<itunes:summary>itunes author</itunes:summary>
</channel>
使用 annotation 可以對應成一個 data class。
@RssTag(name = "channel")
data class CustomChannelData(
@RssAttribute(name="customAttr")
val customAttribute: String?,
@RssTag(name="title",order = [OrderType.GOOGLE, OrderType.ITUNES, OrderType.RSS_STANDARD])
val rssTitle: String?,
@RssRawData(["itunes:summary", "googleplay:description", "googleplay:summary"])
val description: String?,
)
我們可以看到在這邊我們指定要爬一個叫 channel 的 tag ,然後把 customAttr
透過 @RssAttribute
放到 customAttribute
的 class property 裡面。 rssTitle
裡面想依序取資料的有 google 、itunes 和 RSS 標準格式,所以 google 平台格式沒取到值才會往下個優先順序去取,依此類推。這個順序的設計可以確保使用者的 rssTitle
可以盡最大可能拿到可用的值。 @RssRawData
也有一樣的設計概念,只是它不限於三大平台格式,使用者塞幾個,他就會依照那個陣列的順序去取值,取不到就會往下一個找,另外, @RssRawData
裡面的字串陣列就是使用者想要取值的候選名單,這個名稱可以隨意自訂。像是上方範例裡面有 ["itunes:summary", "googleplay:description", "googleplay:summary"]
,代表依序尋找和取值放在 description
這個 property 裡面。如此一來,我們可以確保使用者有多個 annotation 對應不同種的情況,也有一個 @RssRawData
專門處理特殊的客製化 tag 需求!